{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "---\n",
    "title: Lifetimes and references\n",
    "sidebar_position: 4\n",
    "description: Working with lifetimes and references.\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::note Work in progress\n",
    "\n",
    "Both lifetimes and references are a work in progress and subject to change in\n",
    "future releases. \n",
    "\n",
    ":::\n",
    "\n",
    "In Mojo, _lifetime_ has two meanings: \n",
    "\n",
    "- In general terms, a value's lifetime refers to the span of time when the \n",
    "  value is valid. \n",
    "\n",
    "- It also refers to a specific type of parameter value used to help track the \n",
    "  lifetimes of values and references to values. For clarity, we'll use\n",
    "  `lifetime` in code font to refer to the type.\n",
    "\n",
    "The Mojo compiler includes a lifetime checker, a compiler pass that analyzes\n",
    "dataflow through your program. It identifies when variables are valid and \n",
    "inserts destructor calls when a value's lifetime ends.\n",
    "\n",
    "The Mojo compiler uses `lifetime` values to track the validity of references.\n",
    "Specifically, a `lifetime` value answers two questions:\n",
    "\n",
    "- What logical storage location \"owns\" this value?\n",
    "- Can the value be mutated using this reference?\n",
    "\n",
    "For example, consider the following code:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Joan\n"
     ]
    }
   ],
   "source": [
    "fn print_str(s: String):\n",
    "    print(s)\n",
    "\n",
    "name = String(\"Joan\")\n",
    "print_str(name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The line `name = String(\"Joan\")` declares a variable with an identifier (`name`)\n",
    "and logical storage space for a `String` value. When you pass `name` into the\n",
    "`print_str()` function, the function gets an immutable reference to the value. \n",
    "So both `name` and `s` refer to the same logical storage space, and have\n",
    "associated `lifetime` values that lets the Mojo compiler reason about them. \n",
    "\n",
    "Most of the time, `lifetime` values are handled automatically by the compiler. \n",
    "However, in some cases you'll need to interact with `lifetime` values directly:\n",
    "\n",
    "- When working with references—specifically `ref` arguments and `ref` return\n",
    "  values. \n",
    "\n",
    "- When working with types like \n",
    "  [`Reference`](/mojo/stdlib/memory/reference/Reference) or \n",
    "  [`Span`](/mojo/stdlib/utils/span/Span) which are parameterized on the \n",
    "  `lifetime` of the data they refer to.\n",
    "\n",
    "This section covers [`ref` arguments](#ref-arguments) and \n",
    "[`ref` return values](#ref-return-values), which let functions\n",
    "take arguments and provide return values as references with parametric\n",
    "lifetimes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Working with lifetimes\n",
    "\n",
    "Mojo's `lifetime` values are unlike most other values in the language, because\n",
    "they're primitive values, not Mojo structs. Specifying a parameter that takes a \n",
    "`lifetime` value, you can't just say, `l: Lifetime`, because there's no \n",
    "`Lifetime` type. Likewise, because these values are mostly created by the \n",
    "compiler, you can't just create your own `lifetime` value—you usually need to \n",
    "derive a `lifetime` from an existing value.\n",
    "\n",
    "### Lifetime types\n",
    "\n",
    "Mojo supplies a struct and a set of aliases that you can use to specify \n",
    "`lifetime` types. As the names suggest, the `ImmutableLifetime` and \n",
    "`MutableLifetime` aliases represent immutable and mutable lifetimes, \n",
    "respectively:\n",
    "\n",
    "```mojo\n",
    "struct ImmutableRef[lifetime: ImmutableLifetime]:\n",
    "    pass\n",
    "```\n",
    "\n",
    "Or you can use the [`AnyLifetime`](mojo/stdlib/builtin/type_aliases/AnyLifetime)\n",
    "struct to specify a lifetime with parametric mutability:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct ParametricRef[\n",
    "    is_mutable: Bool,\n",
    "    //,\n",
    "    lifetime: AnyLifetime[is_mutable].type\n",
    "]:\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that `AnyLifetime` _isn't a lifetime value_, it's a helper for specifying a \n",
    "`lifetime` **type**. Lifetime types carry the mutability of a reference as a \n",
    "boolean parameter value, indicating whether the lifetime is mutable, immutable,\n",
    "or even with mutability depending on a parameter specified by the enclosing API.\n",
    "\n",
    "The `is_mutable` parameter here is an [infer-only\n",
    "parameter](/mojo/manual/parameters/#infer-only-parameters). It's never\n",
    "specified directly by the user, but always inferred from context. The\n",
    "`lifetime` value is often inferred, as well. For example, the following code\n",
    "creates a [`Reference`](/mojo/stdlib/memory/reference/Reference) to an existing\n",
    "value, but doesn't need to specify a lifetime—the `lifetime` is inferred from\n",
    "the variable passed in to the reference."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "from memory import Reference\n",
    "\n",
    "def use_reference():\n",
    "    a = 10\n",
    "    r = Reference(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### Lifetime values\n",
    "\n",
    "Most `lifetime` values are created by the compiler. As a developer, there are a\n",
    "few ways to specify `lifetime` values:\n",
    "\n",
    "- Static lifetimes. The `ImmutableStaticLifetime` and `MutableStaticLifetime`\n",
    "  aliases are lifetimes that last for the duration of the program. \n",
    "- The `__lifetime_of()` magic function, which returns the lifetime associated\n",
    "  with the value (or values) passed in.\n",
    "- Inferred lifetime. You can use inferred parameters to capture the lifetime\n",
    "  of a value passed in to a function.\n",
    "\n",
    "#### Static lifetimes\n",
    "\n",
    "You can use the static lifetimes `ImmutableStaticLifetime` and \n",
    "`MutableStaticLifetime` when you have a value that should never be destroyed;\n",
    "or when there's no way to construct a meaningful `lifetime` for a value.\n",
    "\n",
    "For an example of the first case, the `StringLiteral` method\n",
    "[`as_string_slice()`](/mojo/stdlib/builtin/string_literal/StringLiteral#as_string_slice)\n",
    "returns a [`StringSlice`](/mojo/stdlib/utils/string_slice/StringSlice) pointing\n",
    "to the original string literal. String literals are static—they're allocated at\n",
    "compile time and never destroyed—so the slice is created with an immutable,\n",
    "static lifetime.\n",
    "\n",
    "Converting an\n",
    "[`UnsafePointer`](/mojo/stdlib/memory/unsafe_pointer/UnsafePointer) into a\n",
    "`Reference` is an example of the second case: the `UnsafePointer`'s data\n",
    "doesn't carry a `lifetime`—one reason that it's considered unsafe—but you need\n",
    "to specify a `lifetime` when creating a `Reference`. In this case, there's no\n",
    "way to construct a meaningful `lifetime` value, so the new `Reference` is\n",
    "constructed with a `MutableStaticLifetime`. Mojo won't destroy this value\n",
    "automatically. As with any value stored using a pointer, it's up to the user to\n",
    "explicitly [destroy the\n",
    "value](/mojo/manual/pointers#destroying-or-removing-values).\n",
    "\n",
    "#### Derived lifetimes\n",
    "\n",
    "Use the `__lifetime_of()` magic function to obtain a value's lifetime. This can \n",
    "be useful, for example, when creating a container type. Consider the `List`\n",
    "type. Subscripting into a list (`list[4]`) returns a reference to the item at\n",
    "the specified position. The signature of the `__getitem__()` method that's\n",
    "called to return the subscripted item looks like this:\n",
    "\n",
    "```mojo\n",
    "fn __getitem__(ref [_]self, idx: Int) -> ref [__lifetime_of(self)] T:\n",
    "```\n",
    "\n",
    "The syntax may be unfamiliar—`ref` arguments and `ref` return values are\n",
    "described in the following sections. For now it's enough to know that \n",
    "the return value is a reference of type `T` (where `T` is the element type\n",
    "stored in the list), and the reference has the same lifetime as the list itself.\n",
    "This means that as long as you hold the reference, the underlying list won't be\n",
    "destroyed.\n",
    "\n",
    ":::note\n",
    "\n",
    "Ideally the returned reference's `lifetime` would be linked to the individual\n",
    "list item, rather than the list itself. Mojo doesn't yet have a mechanism to \n",
    "express this relationship.\n",
    "\n",
    ":::\n",
    "\n",
    "#### Inferred lifetimes\n",
    "\n",
    "The other common way to access a lifetime value is to _infer_ it from the\n",
    "the arguments passed to a function or method. For example, the `Span` type\n",
    "has an associated `lifetime`:\n",
    "\n",
    "```mojo\n",
    "struct Span[\n",
    "    is_mutable: Bool, //,\n",
    "    T: CollectionElement,\n",
    "    lifetime: AnyLifetime[is_mutable].type,\n",
    "](CollectionElementNew):\n",
    "    \"\"\"A non owning view of contiguous data.\n",
    "```\n",
    "\n",
    "One of its constructors creates a `Span` from an existing `List`, and infers\n",
    "its `lifetime` value from the list:\n",
    "\n",
    "```mojo\n",
    "    fn __init__(inout self, ref [lifetime]list: List[T, *_]):\n",
    "        \"\"\"Construct a Span from a List.\n",
    "\n",
    "        Args:\n",
    "            list: The list to which the span refers.\n",
    "        \"\"\"\n",
    "        self._data = list.data\n",
    "        self._len = len(list)\n",
    "```\n",
    "\n",
    "## Working with references\n",
    "\n",
    "You can use the `ref` keyword with arguments and return values to specify a \n",
    "reference with parametric mutability. That is, they can be either mutable or \n",
    "immutable.\n",
    "\n",
    "These references shouldn't be confused with the `Reference` type, which is\n",
    "basically a safe pointer type. A `Reference` needs to be dereferenced, like a \n",
    "pointer, to access the underlying value. A `ref` argument, on the other hand,\n",
    "looks like a `borrowed` or `inout` argument inside the function. A `ref` return\n",
    "value looks like any other return value to the calling function, but it is a\n",
    "_reference_ to an existing value, not a copy.\n",
    "\n",
    "### `ref` arguments\n",
    "\n",
    "The `ref` argument convention lets you specify an argument of parametric\n",
    "mutability: that is, you don't need to know in advance whether the passed\n",
    "argument will be mutable or immutable. There are several reasons you might want\n",
    "to use a `ref` argument:\n",
    "\n",
    "- You want to accept an argument with parametric mutability.\n",
    "\n",
    "- You want to tie the lifetime of one argument to the lifetime of another\n",
    "  argument.\n",
    "\n",
    "- When you want an argument that is guaranteed to be passed in memory: this can\n",
    "  be important and useful for generic arguments that need an identity,\n",
    "  irrespective of whether the concrete type is register passable.\n",
    "\n",
    "The syntax for a `ref` argument is:\n",
    "\n",
    "<code><strong>ref [</strong><var>lifetime</var><strong>]</strong> <var>argName</var>: <var>argType</var></code>\n",
    "\n",
    "The `lifetime` parameter passed inside the square brackets can be replaced with\n",
    "an underscore character (`_`) to indicate that the parameter is _unbound_. Think\n",
    "of it as a wildcard that will accept any lifetime:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_ref(ref [_] a: Int, b: Int) -> Int:\n",
    "    return a+b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also name the lifetime explicitly. This is useful if you want to specify\n",
    "an `ImmutableLifetime` or `MutableLifetime`, or if you want to bind to\n",
    "the `is_mutable` parameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Immutable: Hello\n",
      "Mutable: Goodbye\n"
     ]
    }
   ],
   "source": [
    "def take_str_ref[\n",
    "      is_mutable: Bool, //,\n",
    "      life: AnyLifetime[is_mutable].type\n",
    "    ](ref [life] s: String):\n",
    "    @parameter\n",
    "    if is_mutable:\n",
    "        print(\"Mutable: \" + s)\n",
    "    else:\n",
    "        print(\"Immutable: \" + s)\n",
    "\n",
    "def pass_refs(s1: String, owned s2: String):\n",
    "    take_str_ref(s1)\n",
    "    take_str_ref(s2)\n",
    "\n",
    "pass_refs(\"Hello\", \"Goodbye\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `ref` return values\n",
    "\n",
    "Like `ref` arguments, `ref` return values allow a function to return a mutable\n",
    "or immutable reference to a value. Like a `borrowed` or `inout` argument, these\n",
    "references don't need to be dereferenced.\n",
    "\n",
    "`ref` return values can be an efficient way to handle updating items in a \n",
    "collection. The standard way to do this is by implementing the `__getitem__()`\n",
    "and `__setitem__()` dunder methods. These are invoked to read from and write to \n",
    "a subscripted item in a collection:\n",
    "\n",
    "```mojo\n",
    "value = list[a]\n",
    "list[b] += 10\n",
    "```\n",
    "\n",
    "With a `ref` argument, `__getitem__()` can return a mutable reference that can\n",
    "be modified directly. This has pros and cons compared to using a `__setitem__()`\n",
    "method:\n",
    "\n",
    "- The mutable reference is more efficient—a single update isn't broken up across\n",
    "  two methods. However, the referenced value must be in memory.\n",
    "  \n",
    "- A `__getitem__()`/`__setitem__()` pair allows for arbitrary to be run when\n",
    "  values are retrieved and set. For example, `__setitem__()` can validate or \n",
    "  constrain input values.\n",
    "\n",
    "For example, in the following example, `NameList` has a `get()` method\n",
    "that returns a reference: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dana\n",
      "Dana?\n"
     ]
    }
   ],
   "source": [
    "struct NameList:\n",
    "    var names: List[String]\n",
    "\n",
    "    def __init__(inout self, *names: String):\n",
    "        self.names = List[String]()\n",
    "        for name in names:\n",
    "            self.names.append(name[])\n",
    "\n",
    "    def __getitem__(ref [_] self: Self, index: Int) ->\n",
    "        ref [__lifetime_of(self)] String:\n",
    "        if (index >=0 and index < len(self.names)):\n",
    "            return self.names[index]\n",
    "        else:\n",
    "            raise Error(\"index out of bounds\")\n",
    "\n",
    "def use_name_list():\n",
    "    list = NameList(\"Thor\", \"Athena\", \"Dana\", \"Vrinda\")\n",
    "    print(list[2])\n",
    "    list[2] += \"?\"\n",
    "    print(list[2])\n",
    "\n",
    "use_name_list()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that this update succeeds, even though `NameList` doesn't define a\n",
    "`__setitem__()` method:\n",
    "\n",
    "```mojo\n",
    "list[2] += \"?\"\n",
    "```\n",
    "\n",
    "Also note that the code uses the return value directly each time, rather than\n",
    "assigning the return value to a variable, like this:\n",
    "\n",
    "```mojo\n",
    "name = list[2]\n",
    "```\n",
    "\n",
    "Since a variable needs to own its value, `name` would end up with an owned \n",
    "_copy_ of the value that `list[2]` returns. Mojo doesn't currently have \n",
    "syntax to express that you want to keep the original reference in `name`. This\n",
    "will be added in a future release.\n",
    "\n",
    "In cases where you need to be able to assign the return value to a variable—for\n",
    "example, an iterator which will be used in a `for..in` loop—you might consider \n",
    "returning a `Reference` instead of a `ref` return value. For example, see the \n",
    "[iterator for the `List` \n",
    "type](https://github.com/modularml/mojo/blob/main/stdlib/src/collections/list.mojo#L60).\n",
    "You can assign a `Reference` to a variable, but you need to use the dereference\n",
    "operator (`[]`) to access the underlying value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "nums = List(1, 2, 3)\n",
    "for item in nums: # List iterator returns a Reference\n",
    "    print(item[])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Parametric mutability of return values\n",
    "\n",
    "Another advantage of `ref` return arguments is the ability to support parametric\n",
    "mutability.  For example, recall the signature of the `__getitem__()` method\n",
    "above:\n",
    "\n",
    "```mojo\n",
    "def __getitem__(ref [_] self: Self, index: Int) ->\n",
    "    ref [__lifetime_of(self)] String:\n",
    "```\n",
    "\n",
    "Since the `lifetime` of the return value is tied to the lifetime of `self`, the\n",
    "returned reference will be mutable if the method was called using a\n",
    "mutable reference. The method still works if you have an immutable reference\n",
    "to the `NameList`, but it returns an immutable reference:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Diana\n"
     ]
    }
   ],
   "source": [
    "fn pass_immutable_list(list: NameList) raises:\n",
    "    print(list[2])\n",
    "    # list[2] += \"?\" # Error, this list is immutable\n",
    "\n",
    "def use_name_list_again():\n",
    "    list = NameList(\"Sophie\", \"Jack\", \"Diana\")\n",
    "    pass_immutable_list(list)\n",
    "\n",
    "use_name_list_again()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Without parametric mutability, you'd need to write two versions of \n",
    "`__getitem__()`, one that accepts an immutable `self` and another that accepts\n",
    "a mutable `self`. "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Mojo",
   "language": "mojo",
   "name": "mojo-jupyter-kernel"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "mojo"
   },
   "file_extension": ".mojo",
   "mimetype": "text/x-mojo",
   "name": "mojo"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
